package com.managertrade.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.util.*;

public class BacktestTool {

    private static final double ATR_MULT_STOP = 1.2;
    private static final double ATR_MULT_TP = 2.0;
    private static final int SMA_PERIOD = 60;
    private static final int BOLL_PERIOD = 20;
    private static final int ATR_PERIOD = 14;

    public static void runATRBacktest() throws Exception {
        List<Candle> candles = loadCandlesFromFile("C:\\Users\\21917\\Desktop\\test.txt");
        calculateSMA(candles, SMA_PERIOD);
        calculateBollingerBands(candles, BOLL_PERIOD);
        calculateATR(candles, ATR_PERIOD);

        boolean inPosition = false;
        String positionType = null;
        double entryPrice = 0;
        double stopLoss = 0;
        double takeProfit = 0;
        int wins = 0, losses = 0;

        for (int i = Math.max(SMA_PERIOD, Math.max(BOLL_PERIOD, ATR_PERIOD)); i < candles.size(); i++) {
            Candle c = candles.get(i);
            if (c.sma == null || c.atr == null || c.bollUpper == null) continue;

            if (!inPosition) {
                boolean trendUp = c.close > c.sma;
                if (c.high > c.bollUpper && trendUp) {
                    // 多头进场
                    inPosition = true;
                    positionType = "long";
                    entryPrice = c.close;
                    stopLoss = entryPrice - c.atr * ATR_MULT_STOP;
                    takeProfit = entryPrice + c.atr * ATR_MULT_TP;
                    System.out.printf("➡️ LONG 入场 @ %.2f，止损 %.2f，止盈 %.2f（依据：高破上轨，趋势向上）\n", entryPrice, stopLoss, takeProfit);
                } else if (c.low < c.bollLower && !trendUp) {
                    // 空头进场
                    inPosition = true;
                    positionType = "short";
                    entryPrice = c.close;
                    stopLoss = entryPrice + c.atr * ATR_MULT_STOP;
                    takeProfit = entryPrice - c.atr * ATR_MULT_TP;
                    System.out.printf("⬅️ SHORT 入场 @ %.2f，止损 %.2f，止盈 %.2f（依据：低破下轨，趋势向下）\n", entryPrice, stopLoss, takeProfit);
                }
            } else {
                if (positionType.equals("long")) {
                    if (c.low <= stopLoss) {
                        System.out.printf("❌ LONG 止损退出 @ %.2f\n", c.low);
                        losses++; inPosition = false;
                    } else if (c.high >= takeProfit) {
                        System.out.printf("✅ LONG 止盈退出 @ %.2f\n", c.high);
                        wins++; inPosition = false;
                    }
                } else {
                    if (c.high >= stopLoss) {
                        System.out.printf("❌ SHORT 止损退出 @ %.2f\n", c.high);
                        losses++; inPosition = false;
                    } else if (c.low <= takeProfit) {
                        System.out.printf("✅ SHORT 止盈退出 @ %.2f\n", c.low);
                        wins++; inPosition = false;
                    }
                }
            }
        }

        int total = wins + losses;
        double winRate = total > 0 ? wins * 100.0 / total : 0;
        System.out.printf("\n📊 交易统计：总共 %d 次交易，胜 %d，负 %d，胜率：%.2f%%\n", total, wins, losses, winRate);
    }

    private static List<Candle> loadCandlesFromFile(String filePath) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        List<List<Object>> rawData = mapper.readValue(new File(filePath), List.class);
        List<Candle> candles = new ArrayList<>();
        for (List<Object> k : rawData) {
            candles.add(new Candle(
                    ((Number) k.get(0)).longValue(),
                    Double.parseDouble(k.get(1).toString()),
                    Double.parseDouble(k.get(2).toString()),
                    Double.parseDouble(k.get(3).toString()),
                    Double.parseDouble(k.get(4).toString())
            ));
        }
        return candles;
    }

    private static void calculateSMA(List<Candle> candles, int period) {
        for (int i = period - 1; i < candles.size(); i++) {
            double sum = 0;
            for (int j = i - period + 1; j <= i; j++) sum += candles.get(j).close;
            candles.get(i).sma = sum / period;
        }
    }

    private static void calculateBollingerBands(List<Candle> candles, int period) {
        for (int i = period - 1; i < candles.size(); i++) {
            double sum = 0;
            for (int j = i - period + 1; j <= i; j++) sum += candles.get(j).close;
            double mean = sum / period;
            double variance = 0;
            for (int j = i - period + 1; j <= i; j++)
                variance += Math.pow(candles.get(j).close - mean, 2);
            double std = Math.sqrt(variance / period);
            candles.get(i).bollUpper = mean + 2 * std;
            candles.get(i).bollLower = mean - 2 * std;
        }
    }

    private static void calculateATR(List<Candle> candles, int period) {
        List<Double> trs = new ArrayList<>();
        for (int i = 1; i < candles.size(); i++) {
            Candle prev = candles.get(i - 1);
            Candle curr = candles.get(i);
            double tr = Math.max(curr.high - curr.low,
                    Math.max(Math.abs(curr.high - prev.close), Math.abs(curr.low - prev.close)));
            trs.add(tr);
        }

        for (int i = period; i < candles.size(); i++) {
            double sum = 0;
            for (int j = i - period; j < i; j++) {
                sum += trs.get(j); // 这里 j 从 0 到 trs.size() - 1，安全
            }
            candles.get(i).atr = sum / period;
        }
    }



    static class Candle {
        long timestamp;
        double open, high, low, close;
        Double sma, bollUpper, bollLower, atr;

        public Candle(long timestamp, double open, double high, double low, double close) {
            this.timestamp = timestamp;
            this.open = open;
            this.high = high;
            this.low = low;
            this.close = close;
        }
    }
}
